from math import sin, cos, sqrt

from _global import degToRad

class Vector3(object):
	def __init__(self, *args):
		if len(args) == 3:
			#Convert to list in case args is a tuple
			self._v = list(args)
		elif len(args) == 1:
			self._v = list(args[0])
		else:
			self._v = [0,0,0]
	
	def __str__(self):
		return '(%s, %s, %s)' % (self.x, self.y, self.z)
	
	def __getitem__(self, i):
		return self._v[i]
	def __setitem__(self, i, n):
		self._v[i] = n
	
	def __eq__(self, v2):
		v = self._v
		return v[0] == v2[0] and v[1] == v2[1] and v[2] == v2[2]
	
	def __neg__(self):
		v = self._v
		return Vector3(-v[0], -v[1], -v[2])
	
	def __add__(self, v2):
		"""Vector addition"""
		v = self._v
		return Vector3(v[0] + v2[0], v[1] + v2[1], v[2] + v2[2])
	def __sub__(self, v2):
		"""Vector subtraction"""
		v = self._v
		return Vector3(v[0] - v2[0], v[1] - v2[1], v[2] - v2[2])
	def __mul__(self, s):
		"""Vector scalar multiplication"""
		v = self._v
		return Vector3(v[0] * s, v[1] * s, v[2] * s)
	def __div__(self, s):
		"""Vector scalar division"""
		v = self._v
		return Vector3(v[0] / s, v[1] / s, v[2] / s)
	def __mod__(self, s):
		"""Vector scalar modulo"""
		v = self._v
		return Vector3(v[0] % s, v[1] % s, v[2] % s)
	
	@property
	def x(self): return self._v[0]
	@x.setter
	def x(self, x): self._v[0] = x
	@property
	def y(self): return self._v[1]
	@y.setter
	def y(self, y): self._v[1] = y
	@property
	def z(self): return self._v[2]
	@z.setter
	def z(self, z): self._v[2] = z
	
	def copy(self):
		v = self._v
		return Vector3(v[0], v[1], v[2])
	
	def add(self, v2):
		v = self._v
		v[0] += v2[0]
		v[1] += v2[1]
		v[2] += v2[2]
		return self
	
	def subtract(self, v2):
		v = self._v
		v[0] -= v2[0]
		v[1] -= v2[1]
		v[2] -= v2[2]
		return self
	
	def multiplyScalar(self, n):
		v = self._v
		v[0] *= n
		v[1] *= n
		v[2] *= n
		return self
	
	def multiplyScalarComponents(self, v2):
		v = self._v
		v[0] *= v2[0]
		v[1] *= v2[1]
		v[2] *= v2[2]
		return self
	
	def distFrom(self, v2):
		return sqrt(self.distSqFrom(v2))
	def distSqFrom(self, v2):
		v = self._v
		return (v[0]-v2[0]) ** 2 + (v[1]-v2[1]) ** 2 + (v[2]-v2[2]) ** 2
	
	def rotateX(self, a):
		a *= degToRad

		ny = cos(a) * self.y + sin(a) * self.z
		nz = -sin(a) * self.y + cos(a) * self.z

		self.y = ny
		self.z = nz
		return self

	def rotateY(self, a):
		a *= degToRad

		nx = cos(a) * self.x - sin(a) * self.z
		nz = sin(a) * self.x + cos(a) * self.z

		self.x = nx
		self.z = nz
		return self

	def rotateZ(self, a):
		a *= degToRad

		nx = cos(a) * self.x + sin(a) * self.y
		ny = -sin(a) * self.x + cos(a) * self.y

		self.x = nx
		self.y = ny
		return self
	
	def rotate(self, v2): #This might encounter a gimbal lock problem
		if v2[0]: self.rotateX(v2[0])
		if v2[1]: self.rotateY(v2[1])
		if v2[2]: self.rotateZ(v2[2])
		return self
	
	def magnitude(self):
		return sqrt(self.magnitudeSq())
	def magnitudeSq(self):
		v = self._v
		return v[0]**2 + v[1]**2 + v[2]**2
	
	def normalize(self):
		v = self._v
		m = self.magnitude()
		v[0] /= m
		v[1] /= m
		v[2] /= m
	def getNormal(self):
		v = self._v
		m = self.magnitude()
		return Vector3(v[0] / m, v[1] / m, v[2] / m)
	
	def dot(self, v2):
		v = self._v
		return v[0]*v2[0] + v[1]*v2[1] + v[2]*v2[2]
	
	def cross(self, v2):
		x1, y1, z1 = self._v
		x2, y2, z2 = v2._v
		return Vector3(y1*z2 - z1*y2, z1*x2 - x1*z2, x1*y2 - y1*x2)
